
package com.jf.cloud.order.controller.multishop;


import com.jf.cloud.api.auth.constant.SysTypeEnum;
import com.jf.cloud.api.multishop.feign.ShopWalletFeignClient;
import com.jf.cloud.api.order.constant.OrderStatus;
import com.jf.cloud.common.exception.LuckException;
import com.jf.cloud.common.order.constant.ReturnProcessStatusEnum;
import com.jf.cloud.common.product.constant.PreSaleType;
import com.jf.cloud.common.response.ResponseEnum;
import com.jf.cloud.common.response.ServerResponseEntity;
import com.jf.cloud.common.rocketmq.config.RocketMqConstant;
import com.jf.cloud.common.security.AuthUserContext;
import com.jf.cloud.order.constant.RefundApplyType;
import com.jf.cloud.order.constant.RefundStsType;
import com.jf.cloud.order.constant.RefundType;
import com.jf.cloud.order.constant.SupplierHandleStatus;
import com.jf.cloud.order.dto.multishop.OrderRefundDTO;
import com.jf.cloud.order.model.Order;
import com.jf.cloud.order.model.OrderItem;
import com.jf.cloud.order.model.OrderRefundAddr;
import com.jf.cloud.order.model.OrderSettlement;
import com.jf.cloud.order.service.*;
import com.jf.cloud.order.vo.OrderRefundAddrVO;
import com.jf.cloud.order.vo.OrderRefundVO;
import io.swagger.v3.oas.annotations.Operation;
import ma.glasnost.orika.MapperFacade;
import org.apache.rocketmq.client.producer.LocalTransactionState;
import org.apache.rocketmq.client.producer.TransactionSendResult;
import org.apache.rocketmq.spring.core.RocketMQTemplate;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springdoc.api.annotations.ParameterObject;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.messaging.support.GenericMessage;
import org.springframework.web.bind.annotation.*;

import javax.validation.Valid;
import java.util.List;
import java.util.Objects;


/**
 * @author zz
 */
@RestController("multishopOrderRefundController")
@RequestMapping("/m/order_refund")
public class OrderRefundController {
    private final Logger LOGGER = LoggerFactory.getLogger(OrderRefundController.class);

    @Autowired
    private OrderRefundService orderRefundService;
    @Autowired
    private ShopWalletFeignClient shopWalletFeignClient;
    @Autowired
    private OrderRefundAddrService orderRefundAddrService;
    @Autowired
    private MapperFacade mapperFacade;
    @Autowired
    private RocketMQTemplate orderRefundTemplate;
    @Autowired
    private OrderSettlementService orderSettlementService;
    @Autowired
    private OrderItemService orderItemService;
    @Autowired
    private OrderService orderService;
//
//    /**
//     * 查看我的退款订单列表
//     */
//    @GetMapping("/page")
//    @Operation(summary = "我的退款订单列表" , description = "我的退款订单列表，显示数量")
//    public ServerResponseEntity<EsPageVO<EsOrderRefundVO>> list(PageDTO page, OrderRefundSearchDTO orderRefundPageDTO) {
//        orderRefundPageDTO.setShopId(AuthUserContext.get().getTenantId());
//        orderRefundPageDTO.setSysType(AuthUserContext.get().getSysType());
//        EsPageVO<EsOrderRefundVO> pageList = orderRefundService.page(page, orderRefundPageDTO);
//        return ServerResponseEntity.success(pageList);
//    }

    /**
     * 通过id查询
     *
     * @param refundId id
     * @return 查询详细信息
     */
    @GetMapping("/info/{refundId}")
    public ServerResponseEntity<OrderRefundVO> getById(@ParameterObject @PathVariable("refundId") Long refundId) {
        OrderRefundVO orderRefund = orderRefundService.getDetailByRefundId(refundId);
        if (!Objects.equals(orderRefund.getShopId(), AuthUserContext.get().getTenantId())) {
            LOGGER.error("非法访问，当前用户的租户id为：{}，但是请求的退款单的租户id为：{}", AuthUserContext.get().getTenantId(), orderRefund.getShopId());
            return ServerResponseEntity.fail(ResponseEnum.UNAUTHORIZED);
        }
        if (Objects.equals(orderRefund.getApplyType(), RefundApplyType.REFUND_AND_RETURNS.value())&& orderRefund.getHandelTime() !=null) {
            OrderRefundAddr orderRefundAddr = orderRefundAddrService.getByRefundId(refundId);
            orderRefund.setOrderRefundAddr(mapperFacade.map(orderRefundAddr, OrderRefundAddrVO.class));
            LOGGER.info("退货退款的退款单详情：{}", orderRefund);
        }
        return ServerResponseEntity.success(orderRefund);
    }


    /**
     * 进入这个方法，会出现两种情况：
     * 1. 仅退款，此时商家同意买家的退款申请，执行发放退款的操作
     * 2. 退货退款操作:
     *   2.1)退货退款的第一步，商家允许买家退款的申请，商家进行设置退货地址，不执行发放退款的操作
     *   2.2)退货退款的第二步，当商家收到货之后，同意买家退款，此时需要发放退款，但不会执行这个方法，执行的是下面这个方法
     *   @see com.jf.cloud.order.controller.multishop.OrderRefundController#returnMoney(OrderRefundDTO)
     *
     */
    @PutMapping("/return_and_refund_audit")
    public ServerResponseEntity<Void> returnAndRefundAudit(@RequestBody OrderRefundDTO orderRefundParam) {
        // 处理退款操作
        OrderRefundVO orderRefundVO = orderRefundService.getDetailByRefundId(orderRefundParam.getRefundId());
        if (!Objects.equals(ReturnProcessStatusEnum.APPLY.value(), orderRefundVO.getReturnMoneySts())) {
            // 订单退款状态已发生改变，请勿重复操作
            LOGGER.error("订单退款状态已发生改变，请勿重复操作，订单退款单详情：{}", orderRefundVO);
            return ServerResponseEntity.showFailMsg("订单退款状态已发生改变，请勿重复操作");
        }
        if (!Objects.equals(orderRefundVO.getShopId(), AuthUserContext.get().getTenantId())) {
            LOGGER.error("非法访问，当前用户的租户id为：{}，但是请求的退款单的租户id为：{}", AuthUserContext.get().getTenantId(), orderRefundVO.getShopId());
            return ServerResponseEntity.fail(ResponseEnum.UNAUTHORIZED);
        }

        // 拒绝退款，可以不需要分布式事务啥的，因为就单纯拒绝，发个通知给用户，做幂等处理就好了
        if (Objects.equals(orderRefundParam.getRefundSts(), RefundStsType.DISAGREE.value())) {
            orderRefundVO.setSupplierHandleStatus(null);
            orderRefundService.disagreeRefund(orderRefundParam, orderRefundVO);
            LOGGER.info("商家拒绝退款，退款单详情：{}", orderRefundVO);
            return ServerResponseEntity.success();
        }
        OrderSettlement orderSettlement = orderSettlementService.getByOrderId(orderRefundVO.getOrderId());
        if (Objects.isNull(orderSettlement)) {
            LOGGER.error("没有查询到支付记录，无法申请退款，退款单详情：{}", orderRefundVO);
            return ServerResponseEntity.showFailMsg("没有查询到支付记录，无法申请退款");
        }
        if(!Objects.equals(orderRefundVO.getSupplierId(),0L)) {
            // 移交供应商处理，改变下状态即可
            if (Objects.equals(orderRefundParam.getSupplierHandleStatus(), SupplierHandleStatus.TRANSFER_SUPPLIER.value())) {
                orderRefundService.transferRefundOrderToSupplier(orderRefundParam, orderRefundVO);
                LOGGER.info("移交供应商处理退款，退款单详情：{}", orderRefundVO);
                return ServerResponseEntity.success();
            }
            if(!Objects.equals(orderRefundParam.getSupplierHandleStatus(), SupplierHandleStatus.NORMAL.value())){
                LOGGER.error("供应商订单只能选择自行处理或者移交供应商处理，退款单详情：{}", orderRefundVO);
                return ServerResponseEntity.showFailMsg("供应商订单只能选择自行处理或者移交供应商处理");
            }
            Order order = orderService.getOrderByOrderIdAndUserId(orderRefundVO.getOrderId(), orderRefundVO.getUserId());
            // 不是待采购状态的供应商订单，才检查下钱是否足够
            if(!Objects.equals(order.getWaitPurchase(),1)) {
                // 检查一下商家结算金额是否足够
                ServerResponseEntity<Long> amountResp = shopWalletFeignClient.getSettlementAmountByShopId(orderRefundVO.getShopId());
                if (!amountResp.isSuccess()) {
                    LOGGER.error("查询商家结算金额失败，失败原因：{}", amountResp.getMsg());
                    throw new LuckException(amountResp.getMsg());
                }
                // 供应商改变金额 = 供应商改变金额 - 平台供应商佣金改变量 + 运费
                Long supplierRealRefundAmount = orderRefundVO.getPurchaseRefundAmount() - orderRefundVO.getPurPlatformRefundCommission()
                        + order.getFreightAmount();
                if (amountResp.getData() < supplierRealRefundAmount) {
                    LOGGER.error("商家余额不足，商家结算金额：{}，供应商实际退款金额：{}", amountResp.getData(), supplierRealRefundAmount);
                    return ServerResponseEntity.showFailMsg("商家余额不足，请去进行充值后重试");
                }
            }
        }

        // 同意退货，可以不需要分布式事务啥的，因为就单纯拒绝，发个通知给用户，做幂等处理就好了
        if (Objects.equals(orderRefundVO.getApplyType(), RefundApplyType.REFUND_AND_RETURNS.value())) {
            LOGGER.info("商家同意退货，退款单详情：{}", orderRefundVO);
            orderRefundService.agreeReturns(orderRefundParam, orderRefundVO, SysTypeEnum.MULTISHOP.value());
            return ServerResponseEntity.success();
        }

        // 同意退款，上面只是同意退货，关系到钱要看下面的
        return orderRefundService.agreeRefund(orderRefundParam,orderRefundVO);
    }

    @GetMapping("/is_last_refund")
    @Operation(summary = "是否为最后一单退款")
    public ServerResponseEntity<Boolean> isLastRefund(@ParameterObject Long refundId) {
        Long shopId = AuthUserContext.get().getTenantId();
        return ServerResponseEntity.success(orderRefundService.getIsLastRefund(refundId, shopId));
    }


    /**
     * 退货退款的第二步，当商家收到货之后，同意买家退款，此时需要发放退款
     */
    @PutMapping("/return_money")
    public ServerResponseEntity<Void> returnMoney(@Valid @RequestBody OrderRefundDTO orderRefundParam) {

        // 获取退款单信息
        OrderRefundVO orderRefundVO = orderRefundService.getDetailByRefundId(orderRefundParam.getRefundId());
        if (!Objects.equals(ReturnProcessStatusEnum.CONSIGNMENT.value(), orderRefundVO.getReturnMoneySts())) {
            LOGGER.error("订单退款状态已发生改变，请勿重复操作，退款单详情：{}", orderRefundVO);
            throw new LuckException("订单退款状态已发生改变，请勿重复操作");
        }
        if (!Objects.equals(orderRefundVO.getShopId(), AuthUserContext.get().getTenantId())) {
            LOGGER.error("商家只能操作自己店铺的退款单，退款单详情：{}", orderRefundVO);
            throw new LuckException(ResponseEnum.UNAUTHORIZED);
        }
        // 拒绝退款，可以不需要分布式事务啥的，因为就单纯拒绝，发个通知给用户，做幂等处理就好了
        if (Objects.equals(orderRefundParam.getRefundSts(), RefundStsType.DISAGREE.value())) {
            orderRefundVO.setSupplierHandleStatus(null);
            orderRefundService.disagreeRefund(orderRefundParam, orderRefundVO);
            LOGGER.info("商家拒绝退款");
            return ServerResponseEntity.success();
        }
        OrderSettlement orderSettlement = orderSettlementService.getByOrderId(orderRefundVO.getOrderId());
        if (orderSettlement == null) {
            LOGGER.error("没有查询到支付记录，无法申请退款，退款单详情：{}", orderRefundVO);
            return ServerResponseEntity.showFailMsg("没有查询到支付记录，无法申请退款");
        }
        if(!Objects.equals(orderRefundVO.getSupplierId(),0L) && Objects.equals(orderRefundVO.getSupplierHandleStatus(), SupplierHandleStatus.NORMAL.value())) {
            // 商家自行处理的退款订单，在退货退款的最后一步在检查一下商家结算金额是否足够
            ServerResponseEntity<Long> amountResp = shopWalletFeignClient.getSettlementAmountByShopId(orderRefundVO.getShopId());
            if (!amountResp.isSuccess()) {
                LOGGER.error("查询商家结算金额失败，失败原因：{}", amountResp.getMsg());
                throw new LuckException(amountResp.getMsg());
            }
            Order order = orderService.getOrderByOrderIdAndUserId(orderRefundVO.getOrderId(), orderRefundVO.getUserId());
            // 供应商改变金额 = 供应商改变金额 - 平台供应商佣金改变量
            Long supplierRealRefundAmount = orderRefundVO.getPurchaseRefundAmount() - orderRefundVO.getPurPlatformRefundCommission() + order.getFreightAmount();
            if (amountResp.getData() < supplierRealRefundAmount) {
                LOGGER.error("商家余额不足自行处理供应商订单退款，请去进行充值后重试，退款单详情：{}", orderRefundVO);
                return ServerResponseEntity.showFailMsg("商家余额不足自行处理供应商订单退款，请去进行充值后重试");
            }
        }
        return orderRefundService.agreeRefund(orderRefundParam,orderRefundVO);
    }

//    /**
//     * 退款处理-发放退款
//     * @param refundSnDto
//     * @return
//     */
//    @PutMapping("/refund_request")
//    public ServerResponseEntity<Void> resfundRequest(@Valid @RequestBody RefundSnDto refundSnDto) {
//        // 获取退款信息
//        OrderRefundVO orderRefundVO = orderRefundService.getDetailByRefundId(refundSnDto.getRefundId());
//        if (orderRefundVO == null) {
//            // 退款单不存在
//            throw new LuckException("退款单不存在");
//        }
//        if (orderRefundVO.getDecisionTime() == null) {
//            // 请先确定退款，才能发起退款操作
//            throw new LuckException("请先确定退款，才能发起退款操作");
//        }
//        if (orderRefundVO.getRefundTime() != null) {
//            // 已退款成功，无法再申请退款操作
//            throw new LuckException("已退款成功，无法再申请退款操作");
//        }
//        if (!Objects.equals(orderRefundVO.getShopId(), AuthUserContext.get().getTenantId())) {
//            throw new LuckException(ResponseEnum.UNAUTHORIZED);
//        }
//        if(orderRefundVO.getRefundStatus() == 2){
//            // 已退款成功，无法再申请退款操作
//            throw new LuckException("已退款成功，无法再申请退款操作");
//        }
//        if (Objects.equals(-1,orderRefundVO.getReturnMoneySts())) {
//            // 买家已取消申请
//            throw new LuckException("买家已取消申请");
//        }
//        return agreeRefund(null, orderRefundVO);
//    }

    private ServerResponseEntity<Void> agreeRefund(OrderRefundDTO orderRefundParam, OrderRefundVO orderRefundVo) {

        OrderSettlement orderSettlement = orderSettlementService.getByOrderId(orderRefundVo.getOrderId());
        if (orderSettlement == null) {
            return ServerResponseEntity.showFailMsg("没有查询到支付记录，无法申请退款");
        }
        orderRefundVo.setPayId(orderSettlement.getPayId());
        orderRefundVo.setPayType(orderSettlement.getPayType());

        // -----最后一件运费计算-----------
        long freightAmount = 0L;
        orderRefundVo.setFreightAmount(0L);
        // 获取订单信息
        Order order = orderService.getOrderByOrderIdAndUserId(orderRefundVo.getOrderId(), orderRefundVo.getUserId());
        if (Objects.equals(order.getStatus(), OrderStatus.PAYED.value())) {
            // 如果存在分销订单，则计算分销总金额
            List<OrderItem> orderItemList = orderItemService.listOrderItemsByOrderIds(order.getOrderId());
            // 获取所有的订单项总数
            int orderItemCount = orderItemList.size();
            //退款成功总数
            // 获取所有正在进行中的退款订单
            int refundCount = orderRefundService.countSuccessItemNum(order.getOrderId());
            //最后一单
            if (Objects.equals(refundCount, orderItemCount - 1)) {
                if (order.getFreightAmount() > 0.0 && order.getPlatformFreeFreightAmount() >= 0.0) {
                    freightAmount = order.getFreightAmount() - order.getPlatformFreeFreightAmount();
                }
                // 单项退款，且平台减免运费---平台减免的运费要从商家钱包退还给平台，所以将运费添加到平台优惠金额中
                if (Objects.equals(orderRefundVo.getRefundType(),RefundType.SINGLE.value()) && order.getPlatformFreeFreightAmount() > 0.0) {
                    orderRefundVo.setPlatformRefundAmount(orderRefundVo.getPlatformRefundAmount() + order.getPlatformFreeFreightAmount());
                }
            }
            // 供应商发货的订单，放进去实际的支付运费金额，用于后续的供应商金额退款
            if(Objects.equals(order.getSupplierDeliveryType(),1) && !Objects.equals(order.getSupplierId(),0L)){
                orderRefundVo.setFreightAmount(freightAmount + Math.abs(order.getFreeFreightAmount()));
            }
        }
        // 如果是定金预售，需要注意下是两笔退款
        if(Objects.equals(order.getPreSaleType(), PreSaleType.DEPOSIT.value())){
            orderRefundVo.setPayIds(orderSettlement.getPayIds());
        }
        // 只有单个退款才需要加上运费
        if(Objects.equals(orderRefundVo.getRefundType(),RefundType.SINGLE.value())) {
            orderRefundVo.setRefundAmount(orderRefundVo.getRefundAmount() + freightAmount);
        }
//        orderRefundVo.setPurchaseRefundAmount(orderRefundVo.getPurchaseRefundAmount() + freightAmount);
        // 执行退款，真正意义上的退款，需要确保
        // 发送事务消息
        TransactionSendResult transactionSendResult = orderRefundTemplate.sendMessageInTransaction(RocketMqConstant.ORDER_REFUND_TOPIC, new GenericMessage<>(orderRefundVo), orderRefundParam);

        if (!Objects.equals(transactionSendResult.getLocalTransactionState(), LocalTransactionState.COMMIT_MESSAGE)) {
            return ServerResponseEntity.fail(ResponseEnum.EXCEPTION);
        }
        return ServerResponseEntity.success();
    }


}
